
/*
 * __remove_hrtimer - internal function to remove a timer
 *
 * Caller must hold the base lock.
 *
 * High resolution timer mode reprograms the clock event device when the
 * timer is the one which expires next. The caller can disable this by setting
 * reprogram to zero. This is useful, when the context does a reprogramming
 * anyway (e.g. timer interrupt)
 */
static void __remove_hrtimer(struct hrtimer *timer,
                             struct hrtimer_clock_base *base,
                             u8 newstate, int reprogram)
{
    struct hrtimer_cpu_base *cpu_base = base->cpu_base;
    u8 state = timer->state;

    /* Pairs with the lockless read in hrtimer_is_queued() */
    WRITE_ONCE(timer->state, newstate);
    if (!(state & HRTIMER_STATE_ENQUEUED))
        return;

    if (!timerqueue_del(&base->active, &timer->node))
        cpu_base->active_bases &= ~(1 << base->index);

    /*
     * Note: If reprogram is false we do not update
     * cpu_base->next_timer. This happens when we remove the first
     * timer on a remote cpu. No harm as we never dereference
     * cpu_base->next_timer. So the worst thing what can happen is
     * an superfluous call to hrtimer_force_reprogram() on the
     * remote cpu later on if the same timer gets enqueued again.
     */
    if (reprogram && timer == cpu_base->next_timer)
        hrtimer_force_reprogram(cpu_base, 1);
}

/*
 * remove hrtimer, called with base lock held
 */
static inline int remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base,
               bool restart, bool keep_local)
{
    u8 state = timer->state;

    if (state & HRTIMER_STATE_ENQUEUED)
    {
        bool reprogram;

        /*
         * Remove the timer and force reprogramming when high
         * resolution mode is active and the timer is on the current
         * CPU. If we remove a timer on another CPU, reprogramming is
         * skipped. The interrupt event on this CPU is fired and
         * reprogramming happens in the interrupt handler. This is a
         * rare case and less expensive than a smp call.
         */
        debug_deactivate(timer);
        reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases);

        /*
         * If the timer is not restarted then reprogramming is
         * required if the timer is local. If it is local and about
         * to be restarted, avoid programming it twice (on removal
         * and a moment later when it's requeued).
         */
        if (!restart)
            state = HRTIMER_STATE_INACTIVE;
        else
            reprogram &= !keep_local;

        __remove_hrtimer(timer, base, state, reprogram);
        return 1;
    }
    return 0;
}
